home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
fish
/
001-100
/
001-025
/
020
/
amigatoatari
/
convert.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-17
|
10KB
|
572 lines
/* convert.c */
#include <stdio.h>
#include "convert.h"
extern int debug; /* 1: print debugging messages */
extern int printing; /* 1: print conversion statistics */
Hinfo *ahinfo();
/* hunk information */
Hinfo **hunk; /* -> vector of ptrs to Hinfo structs */
Hinfo *firsthunk; /* -> first hunk */
int nhunks; /* #hunks in input file */
int curhunk; /* current hunk# */
int hvalid; /* state variable (to bump curhunk) */
long filpos; /* position in input file */
long siz[3]; /* segment sizes */
/* relocation (fixup) information */
long rsize; /* total size of all relocation information */
long *rbuf; /* -> buffer for relocation information */
long *rpos; /* current position in relocation info buffer */
char buf[BUFFERSIZE]; /* buffer for copying stuff */
/*
* Convert AMIG* binary loadfile to GEMDOS .PRG executable.
*/
convert(ifd, ofd)
int ifd, ofd;
{
/* init globals */
hunk = (Hinfo **)NULL;
firsthunk = (Hinfo *)NULL;
hvalid = nhunks = curhunk = 0;
filpos = 0L;
rsize = 0L;
pass1(ifd);
if (curhunk < nhunks)
panic("Bugcheck: not enough hunks in input body.");
bind();
if ((rbuf = (long *)malloc((int)rsize)) == NULL)
allerr((int)rsize);
rpos = rbuf;
output(ifd, ofd);
reloc(ifd, ofd);
release();
}
/*
* Parse hunks in AMIG* binary loadfile,
* gather information about it.
*/
pass1(ifd)
int ifd;
{
long lw, junk;
Hinfo *h;
DEBUG("~ pass1()\n");
for(;;)
{
if (readlong(ifd, &lw) == EOF)
break;
switch ((int)lw)
{
case HUNKUNIT:
case HUNKNAME:
DEBUG("~\tHUNKUNIT or HUNKNAME\n");
getlong(ifd, &lw);
skip(ifd, lw * 4);
break;
case HUNKCODE:
chkhunk();
h = hunk[curhunk];
getlong(ifd, &lw); /* get size (in longs) */
lw *= 4;
h->hsize = lw;
h->hpos = filpos;
h->htype = TEXT;
skip(ifd, lw);
if (debug) dumphinfo(h);
break;
case HUNKDATA:
chkhunk();
h = hunk[curhunk];
getlong(ifd, &lw); /* get size (in longs) */
lw *= 4;
h->hsize = lw;
h->hpos = filpos;
h->htype = DATA;
skip(ifd, lw);
if (debug) dumphinfo(h);
break;
case HUNKBSS:
chkhunk();
h = hunk[curhunk];
getlong(ifd, &lw); /* get size (in longs) */
h->hsize = lw * 4;
h->htype = BSS;
if (debug) dumphinfo(h);
break;
case HUNKR32:
h = hunk[curhunk];
for (;;)
{
getlong(ifd, &lw);
if (!lw) break;
lw = (lw + 1) * 4;
h->hrsize += lw + 4;
skip(ifd, lw);
}
h->hrsize += 4;
rsize += h->hrsize + 4;
if(debug)printf("~\thrsize = %ld\n", h->hrsize);
break;
case HUNKR16:
panic("16-bit relocation not supported.");
break;
case HUNKR8:
panic("8-bit relocation not supported.");
break;
case HUNKEXT:
panic("External symbols not supported.");
break;
case HUNKSYMBOL:
panic("Symbols not supported.");
break;
case HUNKDEBUG:
panic("Debug blocks not supported.");
break;
case HUNKEND:
if (hvalid)
{
hvalid = 0;
++curhunk;
}
if(debug)printf("~HUNKEND, curhunk = %d\n", curhunk);
break;
case HUNKHEADER:
header(ifd);
break;
case HUNKOVERLAY:
panic("Overlays not supported.");
break;
case HUNKBREAK:
panic("Breaks (overlays) not supported.");
break;
}
}
}
/*
* Sanity check about hunk adjacency (which may not be a
* problem) and hunk number range.
*/
chkhunk()
{
if (hvalid)
panic("Bugcheck: two adjacent hunks w/o HUNKEND!");
if (curhunk >= nhunks)
panic("Bugcheck: too many hunks!");
hvalid = 1;
}
/*
* Read hunk header,
* get info for global vars.
*
*/
header(fd)
int fd;
{
long lw, *p;
long htabsize, firsthunk, lasthunk;
unsigned int i, j;
/*
* Skip library names.
*/
for (;;)
{
getlong(fd, &lw);
if (!lw) break;
skip(fd, lw*4);
}
/* more random header info */
getlong(fd, &htabsize);
getlong(fd, &firsthunk);
getlong(fd, &lasthunk);
if (debug)
printf("~\thtabsize = %ld\n\tfirsthunk = %ld\n\tlasthunk = %ld\n",
htabsize, firsthunk, lasthunk);
/* alloc space for hunk database */
nhunks = (unsigned)(lasthunk - firsthunk + 1);
hunk = (Hinfo **)malloc(nhunks * sizeof(Hinfo));
if (hunk == NULL)
allerr(nhunks * sizeof(Hinfo));
for (j = 0; j < nhunks; ++j)
{
hunk[j] = ahinfo();
hunk[j]->hunkno = j;
getlong(fd, &hunk[j]->hsize);
if(debug) printf("~\t%d hsize = %ld ($%lx)\n",
j, hunk[j]->hsize, hunk[j]->hsize);
}
}
/*
* Compute hunk order and starting addresses.
*/
bind()
{
int typ, hnk;
long addr;
Hinfo *hptr;
DEBUG("~ bind()\n");
addr = 0L;
hptr = firsthunk;
for (typ = 0; typ < 3; ++typ)
{
siz[typ] = 0L;
for (hnk = 0; hnk < nhunks; ++hnk)
if (hunk[hnk]->htype == typ)
{
if (firsthunk == (Hinfo *)NULL)
hptr = firsthunk = hunk[hnk];
else {
hptr->hnext = hunk[hnk];
hptr = hunk[hnk];
}
siz[typ] += hptr->hsize;
hptr->haddr = addr;
addr += hptr->hsize;
if(debug)
printf("~\thunk[%d]->haddr = $%lx\n", hnk, hptr->haddr);
}
}
if(printing)
printf("text %ld ($%lx), data %ld ($%lx), bss %ld ($%lx)\n",
siz[0], siz[0], siz[1], siz[1], siz[2], siz[2]);
}
/*
* Generate the GEMDOS output file.
*/
output(ifd, ofd)
int ifd, ofd;
{
int i;
Hinfo *hu;
DEBUG("~ output()\n");
/*
* Write .PRG header.
*/
writeword(ofd, 0x601a);
for (i = 0; i < 3; i++)
writelong(ofd, siz[i]);
for (i = 0; i < 7; i++)
writeword(ofd, 0x0000);
for (hu = firsthunk; hu != NULL; hu = hu->hnext)
if (hu->htype == TEXT || hu->htype == DATA)
{
lseek(ifd, hu->hpos, 0);
randw(ifd, hu->hsize, ofd);
if (hu->hrsize)
{
lseek(ifd, 4L, 1);
*rpos++ = hu->hunkno;
if (read(ifd, rpos, (int)hu->hrsize) != (int)hu->hrsize)
panic("Reloc info read error.");
if(debug)printf("~ relocsiz = %ld\n", hu->hrsize);
rpos += hu->hrsize >> 2;
}
}
}
/*
* Generate relocation information
* (at the end of the output file).
*/
reloc(ifd, ofd)
int ifd, ofd;
{
int cmplong();
long cvt2long();
long *rp, *drp;
char *crp, c;
int i, hno, nel;
long count, base, lw, addr;
DEBUG("~ reloc()\n");
if (debug)
{
i = 0;
for (crp = (char *)rbuf; crp < (char *)rpos; crp += 4)
{
if (!i) printf("~ ");
printf("%02x%02x%02x%02x",
crp[0]&0xff, crp[1]&0xff, crp[2]&0xff, crp[3]&0xff);
if (++i >= 8)
{
printf("\n");
i = 0;
} else putchar(' ');
}
putchar('\n');
}
/*
* Go back into the .PRG file and add
* hunk starting-offsets to the longwords
* that must be fixed up.
* 28L is the size of the GEMDOS .PRG header.
*/
for (rp = rbuf; rp < rpos;)
{
hno = *rp++;
if(debug)printf("~ hno = %d\n", hno);
for (;;)
{
*rp = cvt2long(*rp);
if (!(count = *rp++)) break;
*rp = cvt2long(*rp);
base = hunk[(int)*rp++]->haddr;
if(debug)printf("~ count = %ld, base = $%0lx\n", count, base);
while (count--)
{
*rp = cvt2long(*rp);
if(debug)printf("~ seek(ifd) = %ld, seek(ofd) = %ld ",
hunk[hno]->hpos + *rp,
hunk[hno]->haddr + *rp + 28L);
lseek(ifd, hunk[hno]->hpos + *rp, 0);
lseek(ofd, hunk[hno]->haddr + *rp++ + 28L, 0);
readlong(ifd, &lw);
lw += base;
writelong(ofd, lw);
if(debug)printf("lw = $%0lx\n", lw);
}
}
}
/*
* Compute and sort fixup offsets.
*/
nel = 0;
drp = rbuf;
for (rp = rbuf; rp < rpos;)
{
hno = *rp++;
for (;;)
{
if (!(count = *rp++)) break;
++rp;
while (count--)
{
*drp++ = hunk[hno]->haddr + *rp++;
++nel;
}
}
}
rpos = drp;
qsort(rbuf, nel, 4, cmplong);
/* print sorted info */
if(debug)
{
i = 0;
for (rp = rbuf; rp < rpos; ++rp)
{
if (!i) printf("~ ");
printf("%08lx", *rp);
if (++i >= 8)
{
printf("\n");
i = 0;
} else putchar(' ');
}
putchar('\n');
}
/*
* Write GEMDOS relocation information
*/
lseek(ofd, 0L, 2); /* to end of file */
rp = rbuf;
while (rp < rpos)
{
/* write offset to first fixup */
if (rp == rbuf)
{
writelong(ofd, *rp);
addr = *rp++;
if(debug)printf("$%lx\n", addr);
continue;
}
if (addr >= *rp) panic("Bad relocation information.");
c = 254;
lw = *rp - addr;
addr = *rp++;
if(debug)printf("$%lx:", lw);
while (lw > 254)
{
write(ofd, &c, 1);
lw -= 254L;
if(debug)putchar('+');
}
c = (char)lw;
write(ofd, &c, 1);
if(debug)printf("$%x\n", (int)lw);
}
/*
* Terminate relocation list
*/
c = 0;
write(ofd, &c, 1);
}
/*
* Compare two longs
* for qsort().
*/
cmplong(l1, l2)
long *l1, *l2;
{
return *l1 - *l2;
}
/*
* Allocate (and initialize) a Hinfo node.
*/
Hinfo *ahinfo()
{
Hinfo *h;
if (curhunk >= nhunks)
panic("curhunk >= nhunks, too many hunks!");
if ((h = (Hinfo *)malloc(sizeof(Hinfo))) == NULL)
allerr(sizeof(Hinfo));
h->hsize = 0L;
h->hpos = 0L;
h->haddr = 0L;
h->hrsize = 0L;
h->htype = -1;
h->hrel = (long *)NULL;
h->hnext = (Hinfo *)NULL;
return h;
}
/*
* Release memory used by hunk database.
*/
release()
{
int i;
for (i = 0; i < nhunks; ++i)
{
if (hunk[i]->hrel != NULL)
free(hunk[i]->hrel);
free(hunk[i]);
}
free(hunk);
}
/*
* Skip some of the input file
*/
skip(fd, count)
int fd;
long count;
{
filpos += count;
lseek(fd, count, 1);
}
/*
* Out of memory (malloc() didn't work);
* complain and die.
*/
allerr(size)
int size;
{
fprintf (stderr, "malloc(%d) failed..\n", size);
panic("Allocation failure, heap exhausted, I give up!\n");
}
/*
* Print information about an Hinfo node.
*/
dumphinfo(h)
Hinfo *h;
{
printf("~\thsize = %ld ($%lx), hpos = %ld, haddr = %ld ($%lx)\n",
h->hsize, h->hsize, h->hpos, h->haddr, h->haddr);
printf("~\thtype = %d ", h->htype);
printf("hrel = $%lx, hnext = $%lx\n",
(long)h->hrel, (long)h->hnext);
}
/*
* Convert 68000 long to local long
*/
long cvt2long(lw)
long lw;
{
#ifdef AMIGA
return (lw);
#else
char *out, *in;
long olw;
/*
* 8086/VAX conversion
*/
in = (char *)&lw;
out = (char *)&olw;
out[0] = in[3];
out[1] = in[2];
out[2] = in[1];
out[3] = in[0];
return olw;
#endif /* AMIGA */
}